#include "chttpclient.h"

#if defined(_WIN32)
//add pre define BUILDING_LIBCURL libcurl.lib ws2_32.lib wldap32.lib
//Normaliz.lib
//Crypt32.lib

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")
#pragma comment(lib, "Normaliz.lib")
#pragma comment(lib, "Crypt32.lib")


#if _MSC_VER == 1600 //vs2010
#pragma comment(lib, "../curlwrapper/exlibs/libcurl-vc10-x86-release-static-zlib-static-ipv6-sspi-winssl/lib/libcurl_a.lib")
#elif _MSC_VER >= 1900
#pragma comment(lib, "../curlwrapper/exlibs/libcurl-vc15-x86-release-static-zlib-static-ipv6-sspi-winssl/lib/libcurl_a.lib")
#endif

#endif // _WIN32

int CHttpClient::OnDebug(CURL *, curl_infotype itype, char * pData, size_t , void *)
{
    if(itype == CURLINFO_TEXT)
    {
        //printf("[TEXT]%s\n", pData);
    }
    else if(itype == CURLINFO_HEADER_IN)
    {
        printf("[HEADER_IN]%s\n", pData);
    }
    else if(itype == CURLINFO_HEADER_OUT)
    {
        printf("[HEADER_OUT]%s\n", pData);
    }
    else if(itype == CURLINFO_DATA_IN)
    {
        printf("[DATA_IN]%s\n", pData);
    }
    else if(itype == CURLINFO_DATA_OUT)
    {
        printf("[DATA_OUT]%s\n", pData);
    }
    return 0;
}

size_t CHttpClient::OnWriteDataS(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
    std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
    if( NULL == str || NULL == buffer ){
        return -1;
    }

    char* pData = (char*)buffer;
    str->append(pData, size * nmemb);
    return nmemb;
}

size_t CHttpClient::OnWriteDataF(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
    FILE* fp = dynamic_cast<FILE*>(*(FILE **)lpVoid);
    if( NULL == fp || NULL == buffer ){
        return -1;
    }

    return fwrite(buffer, size, nmemb, fp);
}


///////////////////////////////////////////////////////////////////////////////////////////////

void CHttpClient::SetDebug(bool bDebug)
{
    m_bDebug = bDebug;
}


/*
1. build zlib
##vs2015
nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="inffas32.obj match686.obj"
##vs2010 fuck the bug in zlib masm code.
nmake -f win32/Makefile.msc clean
nmake -f win32/Makefile.msc

2. build libcurl
cd winbuild
nmake /f Makefile.vc mode=static VC=10 with_devel=../../deps_vc10 with_zlib=static DEBUG=no
nmake /f Makefile.vc mode=static VC=15 with_devel=../../deps_vc15 with_zlib=static DEBUG=no

*/

#ifdef _WIN32
#include <windows.h>
#include <Winhttp.h>
int GetHTTPProxyFromIE(const WCHAR* url, /*out*/std::wstring &server);

#pragma comment(lib, "Winhttp.lib")
std::string GetSysProxy(const std::string& strURL)
{
    string ret;

    int buffSize = MultiByteToWideChar(CP_ACP, 0, strURL.c_str(), -1, NULL, 0);
    LPWSTR proxy = new WCHAR[buffSize];
    MultiByteToWideChar(CP_ACP, 0, strURL.c_str(), -1, proxy, buffSize);

    wstring server;
    GetHTTPProxyFromIE(proxy, server);
    delete(proxy);

    int l = ::WideCharToMultiByte(CP_THREAD_ACP, 0, (wchar_t*)
        server.c_str(), -1, NULL, 0, NULL, NULL);
    if (-1 != l) {
        char *temp = new char[l];

        ::WideCharToMultiByte(CP_THREAD_ACP, 0,
            server.c_str(),
            -1, temp, l, NULL,
            NULL);
        ret = temp;
        delete(temp);
    }
    return ret;
}

int GetHTTPProxyFromIE(const WCHAR* url, /*out*/std::wstring &server)
{
    BOOL                      auto_proxy = FALSE;
    WINHTTP_AUTOPROXY_OPTIONS auto_proxy_option;
    WINHTTP_PROXY_INFO        auto_proxy_info;

    ZeroMemory(&auto_proxy_option, sizeof(WINHTTP_AUTOPROXY_OPTIONS));
    ZeroMemory(&auto_proxy_info, sizeof(WINHTTP_PROXY_INFO));

    //  
    // convert URL from mbs to wchar  
    //  
    const WCHAR* url_request = L"http://www.youtube.com";
    if (NULL != url && wcslen(url)>0)
        url_request = url;

    server = L"";

    //  
    // Create the WinHTTP session.  
    //  
    HINTERNET http_session = WinHttpOpen(L"ProxyDetect/1.0",
        WINHTTP_ACCESS_TYPE_NO_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0);

    if (NULL == http_session) {
        return -2;
    }

    if (!WinHttpSetTimeouts(http_session, 30000, 30000, 0, 0)) {
        printf("Error %u in WinHttpSetTimeouts.\n", GetLastError());

        WinHttpCloseHandle(http_session);
        return -3;
    }

    //  
    // Check if need auto proxy.  
    //  
    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config;
    if (WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) {
        if (ie_config.fAutoDetect)
            auto_proxy = TRUE;

        if (NULL != ie_config.lpszAutoConfigUrl) {
            auto_proxy = TRUE;
            auto_proxy_option.lpszAutoConfigUrl = ie_config.lpszAutoConfigUrl;
        }
    } else {
        // Error, Try to auto proxy.  
        auto_proxy = TRUE;
    }

    //  
    // request auto detect to get proxy info.  
    //  
    if (auto_proxy) {
        // Setting auto detect options  
        if (NULL != auto_proxy_option.lpszAutoConfigUrl) {
            auto_proxy_option.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
        } else {
            auto_proxy_option.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
            auto_proxy_option.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
        }

        // basic flags you almost always want  
        auto_proxy_option.fAutoLogonIfChallenged = TRUE;

        // here we reset fAutoProxy in case an auto-proxy isn't actually  
        // configured for this URL  
        auto_proxy = WinHttpGetProxyForUrl(http_session, url_request, &auto_proxy_option, &auto_proxy_info);
    }

    //  
    // Output result  
    //  
    if (auto_proxy) {
        // set proxy options based on auto proxy info.  
        server = auto_proxy_info.lpszProxy;
    } else  if (NULL != ie_config.lpszProxy) {
        // IE has an explicit proxy. set proxy options for libcurl here  
        // based on ieProxyConfig  
        //  
        // note that sometimes IE gives just a single or double colon  
        // for proxy or bypass list, which means "no proxy"  
        server = ie_config.lpszProxy;
    } else {
        // there is no auto proxy and no manually configured proxy  
    }

    //  
    // Clean up.  
    //  
    if (ie_config.lpszAutoConfigUrl != NULL)
        GlobalFree(ie_config.lpszAutoConfigUrl);

    if (auto_proxy_info.lpszProxy != NULL)
        GlobalFree(auto_proxy_info.lpszProxy);

    if (auto_proxy_info.lpszProxyBypass != NULL)
        GlobalFree(auto_proxy_info.lpszProxyBypass);

    if (http_session != NULL)
        WinHttpCloseHandle(http_session);

    return 0;
}

void testchttpclient()
{
    CHttpClient chttpclient;
    string url = "https://www.baidu.com";
    string resp;
    vector<string> mHeader;
    chttpclient.setAutoDecoding("gzip");
    chttpclient.Gets(url, resp, NULL, NULL, mHeader, false);


    printf("%s\n", resp.c_str());
}

#else

std::string GetSysProxy(const std::string& strURL)
{
    return "";
}

#endif

